package es.uned.etsii.si3.taller.servlets;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.opensymphony.xwork2.ActionSupport;

import es.uned.etsii.si3.taller.Empleado;
import es.uned.etsii.si3.taller.FactoriaDAO;
import es.uned.etsii.si3.taller.FactoriaFunciones;
import es.uned.etsii.si3.taller.Usuario;
import es.uned.etsii.si3.taller.Empleado.Categoria;
import es.uned.etsii.si3.taller.misc.ProporcionaFuncionalidad;

public class BusquedaYBajaEmpleados extends ActionSupport {
	private static final long serialVersionUID = 1L;

	private Usuario usuario = null;
	private Empleado empleado = null;
	
	private String         nombreUsuario   = "";
	private String         nombre    = "";
	private String         apellidos = "";
	private String         dni       = "";
	private Categoria      categoria = Categoria.NO_VALIDA;
	private List<Empleado> listaEmpleados;
	private List<Integer> empleadosEscogidos;

	// Getters / Setters
	
	/* BEGIN - getters para ir al formularioEmpleado */
	public boolean getEsEmpleadoNuevo() {
		return false;
	}
	
	public Usuario getUsuario() {
		return usuario;
	}
	
	public Empleado getEmpleado() {
		return empleado;
	}
	/* END - getters para ir al formularioEmpleado */

	public String getNombreUsuario() {
		return nombreUsuario;
	}
	
	public String getNombre() {
		return nombre;
	}

	public String getApellidos() { 
		return apellidos; 
	}

	public String getDni() {
		return dni;
	}
	
	public String getCategoria() {
		return categoria.name();
	}
	
	public List<Empleado> getListaEmpleados() {
		return listaEmpleados;
	}
	
	public Categoria[] getListaCategorias() {
		return Categoria.values();
	}

	public void setNombreUsuario(String nombreUsuario) {
		if (nombreUsuario != null)
			this.nombreUsuario = nombreUsuario.trim();
	}
	
	public void setNombre(String nombre) {
		if (nombre != null)
			this.nombre = nombre.trim();
	}
	
	public void setApellidos(String apellidos) {
		if (apellidos != null)
			this.apellidos = apellidos.trim();
	}
	
	public void setDni(String dni) {
		if (dni != null)
			this.dni = dni.trim();
	}
	
	public void setCategoria(String cat) {
		try {
			categoria = Categoria.valueOf(cat);
		}
		catch (IllegalArgumentException e) {
			categoria = Categoria.NO_VALIDA;
		}
	}
	
	public void setEmpleadosEscogidos(List<Integer> listaEscogidos) {
		empleadosEscogidos = listaEscogidos;
	}
	
	public String display() {
		return NONE;
	}
	
	private String hacerLike(String valor) {
		return "%" + valor + "%";
	}

	/**
	 * Obtiene los empleados que se corresponden a la búsqueda dadad
	 * @return actionerror
	 */
	@Override
	public String execute() {
		if (!hayCondiciones()) {
			addActionMessage("No se puede hacer una consulta sin introducir alguna restricción");
			return SUCCESS;
		}
		
		try {
			boolean doOr = false;

			QueryBuilder<Empleado, Integer> empleadoQb = FactoriaDAO.getQueryBuilder(Empleado.class);
			
			// Esto es para asegurar que se escogen sólo usuarios activos 
			{
				QueryBuilder<Usuario, Integer> usuarioQb = FactoriaDAO.getQueryBuilder(Usuario.class);
				usuarioQb.where().eq(Usuario.ACTIVO_FIELD_NAME, true);
				empleadoQb.join(usuarioQb);
			}

			Where<Empleado, Integer> whereEmpleado = empleadoQb.where();

			if (tieneLongitud(getNombreUsuario())) {
				QueryBuilder<Usuario, Integer> usuarioQb = FactoriaDAO.getQueryBuilder(Usuario.class);
				usuarioQb.selectColumns(Usuario.ID_FIELD_NAME);
				usuarioQb.where().like(Usuario.USUARIO_FIELD_NAME, hacerLike(getNombreUsuario()))
								 .and()
								 .eq(Usuario.ACTIVO_FIELD_NAME, true);

				whereEmpleado.in(Empleado.ID_USUARIO_FIELD_NAME, usuarioQb);
				
				doOr = true;
			}

			if (tieneLongitud(getNombre())) {
				if (doOr) whereEmpleado.or();

				whereEmpleado.like(Empleado.NOMBRE_FIELD_NAME, hacerLike(getNombre()));
				doOr = true;
			}
			
			if (categoria != Categoria.NO_VALIDA) {
				if (doOr) whereEmpleado.or();
				
				whereEmpleado.eq(Empleado.CATEGORIA_FIELD_NAME, categoria);
			}

			if (tieneLongitud(getApellidos())) {
				if (doOr) whereEmpleado.or();

				whereEmpleado.like(Empleado.APELLIDOS_FIELD_NAME, hacerLike(getApellidos()));
			}

			if (tieneLongitud(getDni())) {
				if (doOr) whereEmpleado.or();

				whereEmpleado.like(Empleado.DNI_FIELD_NAME, hacerLike(getDni()));
			}

			listaEmpleados = empleadoQb.query();

			if (listaEmpleados.size() == 0)
				addActionMessage("No se encontraron usuarios que coincidan");
		} catch (SQLException e) {
			addActionError("Al intentar hacer la búsqueda: " + e.toString());
		}
		return SUCCESS;
	}

	// Comprobación rápida para saber si queremos hacer una consulta, o no
	private boolean tieneLongitud(String t) { if (t.length() > 0) return true; return false; }

	private boolean hayCondiciones() {
		if (tieneLongitud(getNombreUsuario()) ||
				(categoria != Categoria.NO_VALIDA) ||
				tieneLongitud(getNombre()) || 
				tieneLongitud(getApellidos()) ||
				tieneLongitud(getDni())
				)
			return true;
		return false;
	}
	
	private List<Empleado> empleadosPorId(List<Integer> listaIds) {
		List<Empleado> lista = new ArrayList<Empleado>();
		try {
			for(Integer indice: listaIds) {
				lista.add(FactoriaDAO.recuperar(Empleado.class, indice.intValue()));
			}
		} catch (SQLException e) {
			addActionError("No se pudo recuperar la lista de empleados: " + e.toString());
			lista = null;
		}
		
		return lista;
	}
	
	/**
	 * Permite modificar los datos de los empleados
	 * @return actionerror
	 */
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_MODIFICAR_EMPLEADO)
	public String modificar() {
		if ((empleadosEscogidos == null) || (empleadosEscogidos.size() == 0)) {
			addActionError("No se ha escogido ningún empleado a eliminar");
			return INPUT;
		}
		
		listaEmpleados = empleadosPorId(empleadosEscogidos);
		
		if (listaEmpleados.size() > 1) {
			addActionError("Sólo puede escoger un empleado para modificar");
			return INPUT;
		}
		
		empleado = listaEmpleados.get(0);
		categoria = empleado.getCategoria();
		usuario = empleado.getUsuario();
		if (usuario == null) {
			addActionError("No se pudo recuperar el usuario del empleado " + empleado.getId() + " con nombre " + empleado.getNombre());
			return INPUT;
		}
		try {
			usuario.refresh();
		} catch (SQLException e) {
			addActionError("No se pudo recuperar el usuario correspondiente al empleado: " + e.toString());
			return INPUT;
		}
		
		return SUCCESS;
	}
	
	/**
	 * Pide confirmación de la baja del empleado
	 * @return actionerror
	 */
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_BAJA_EMPLEADO)
	public String confirmarBaja() {
		if ((empleadosEscogidos == null) || (empleadosEscogidos.size() == 0)) {
			addActionError("No se ha escogido ningún empleado a eliminar");
			return INPUT;
		}
		
		listaEmpleados = empleadosPorId(empleadosEscogidos);
		
		return SUCCESS;
	}
	
	/**
	 * Da de baja (inactiva) a un empleado
	 * @return actionerror
	 */
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_BAJA_EMPLEADO)
	public String darDeBaja() {
		if ((empleadosEscogidos == null) || (empleadosEscogidos.size() == 0)) {
			addActionError("No se ha escogido ningún empleado a eliminar");
			return INPUT;
		}
		
		for(Empleado empleado: empleadosPorId(empleadosEscogidos)) {
			try {
				Usuario usuario = empleado.getUsuario();
				usuario.update();
				
				try {
					usuario.desactivar();
				} catch (SQLException e) {
					addActionError("Error al intentar desactivar al usuario {" + usuario.getUsuario() +
							"}, del que depende el empleado {" + empleado.getNombre() + "}.");
				}
			} catch (SQLException e) {
				addActionError("Error al intentar recuperar el usuario asociado al empleado: " + empleado.getNombre());
			}
		}
		
		if (!hasActionErrors())
			addActionMessage("Dados de baja los empleados con éxito");
		
		return SUCCESS;
	}
}